// Copyright 2019 orivil.com. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found at https://mit-license.org.

package container

import (
	"encoding/json"
	"gitee.com/tugoer/psy-testing/code/models"
	"gitee.com/tugoer/psy-testing/code/utils"
	"github.com/pkg/errors"
	"io/ioutil"
	"os"
	"sync"
)

var uTimeSubjectDir = "data/lists/utime"

var viewSubjectDir = "data/lists/view"

func init() {
	err := os.MkdirAll(uTimeSubjectDir, os.ModePerm)
	if err != nil {
		panic(err)
	}
	err = os.MkdirAll(viewSubjectDir, os.ModePerm)
	if err != nil {
		panic(err)
	}
}

func readSubjectsData(order utils.Order, page string) (data []byte, err error) {
	file, err := subjectPageFile(order, page)
	if err != nil {
		return nil, err
	}
	return ioutil.ReadFile(file)
}

func writeSubjectsData(order utils.Order, page string, data []byte) error {
	file, err := subjectPageFile(order, page)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(file, data, os.ModePerm)
}

func RemoveSubjects() error {
	Subjects.mu.Lock()
	defer Subjects.mu.Unlock()
	err := os.RemoveAll(uTimeSubjectDir)
	if err != nil {
		return err
	}
	err = os.RemoveAll(viewSubjectDir)
	if err != nil {
		return err
	}
	err = os.MkdirAll(uTimeSubjectDir, os.ModePerm)
	if err != nil {
		return err
	}
	err = os.MkdirAll(viewSubjectDir, os.ModePerm)
	if err != nil {
		return err
	}
	Subjects.data = make(map[string][]*models.Subject, 10)
	return nil
}

func subjectPageFile(order utils.Order, page string) (string, error) {
	switch order {
	case utils.UTime:
		return uTimeSubjectDir + "/" + page + ".json", nil
	case utils.View:
		return viewSubjectDir + "/" + page + ".json", nil
	default:
		return "", errors.New("不允许的排序规则: " + string(order))
	}
}

var Subjects = &subjects{data: make(map[string][]*models.Subject, 10)}

type subjects struct {
	data map[string][]*models.Subject
	mu   sync.RWMutex
}

func (ec *subjects) Get(order utils.Order, page string) (subjects []*models.Subject, err error) {
	ec.mu.Lock()
	defer ec.mu.Unlock()
	key := string(order) + page
	subjects = ec.data[key]
	if subjects == nil {
		// 本地获取数据
		data, err := readSubjectsData(order, page)
		if err != nil {
			if os.IsNotExist(err) {
				// 拉取远程数据
				data, err := utils.GetSubjects(page, order)
				if err != nil {
					return nil, err
				} else {
					err = json.Unmarshal(data, &subjects)
					if err != nil {
						return nil, err
					}
					err = writeSubjectsData(order, page, data)
					if err != nil {
						return nil, err
					}
				}
			} else {
				return nil, err
			}
		} else {
			// 解析本地数据
			err = json.Unmarshal(data, &subjects)
			if err != nil {
				return nil, err
			}
		}
		ec.data[key] = subjects
	}
	return subjects, nil
}
